#include "MyShellLexicalAnalyzer.h"
#include "MyShellGlobalVariables.h"

#include <iostream>

MY_SHELL_NAMESPACE_BEGIN
// 关键字转单词类型
std::unordered_map<std::string, mysh::WORD_TYPE> mysh_keyword_to_word_type = {
    {"function", mysh::WORD_TYPE::FUNCTION}, 
    {"declare", mysh::WORD_TYPE::DECLARE}, 
    {"for", mysh::WORD_TYPE::FOR}, 
    {"in", mysh::WORD_TYPE::IN}, 
    {"to", mysh::WORD_TYPE::TO}, 
    {"BzzD", mysh::WORD_TYPE::TO}, 
    {"if", mysh::WORD_TYPE::IF}, 
    {"elif", mysh::WORD_TYPE::ELIF}, 
    {"else", mysh::WORD_TYPE::ELSE}, 
    {"call", mysh::WORD_TYPE::CALL}, 
    {"return", mysh::WORD_TYPE::RETURN}, 
    {"run", mysh::WORD_TYPE::RUN}, 
    {"input", mysh::WORD_TYPE::INPUT}, 
    {"output", mysh::WORD_TYPE::OUTPUT}, 
    {"int", mysh::WORD_TYPE::INT},
    {"string", mysh::WORD_TYPE::STRING},
    {"array", mysh::WORD_TYPE::ARRAY},
    {"bool", mysh::WORD_TYPE::BOOL}, 
    {"void", mysh::WORD_TYPE::VOID}, 
    {"true", mysh::WORD_TYPE::TRUE}, 
    {"false", mysh::WORD_TYPE::FALSE}
};

// 单字符转单词类型
std::unordered_map<char, mysh::WORD_TYPE> mysh_single_character_to_word_type = {
    {';', mysh::WORD_TYPE::SEMICOLON}, 
    {'(', mysh::WORD_TYPE::LEFT_PARENTHESES}, 
    {')', mysh::WORD_TYPE::RIGHT_PARENTHESES}, 
    {'[', mysh::WORD_TYPE::LEFT_SQUARE_BRACKETS}, 
    {']', mysh::WORD_TYPE::RIGHT_SQUARE_BRACKETS}, 
    {'{', mysh::WORD_TYPE::LEFT_BRACE}, 
    {'}', mysh::WORD_TYPE::RIGHT_BRACE}, 
    {'=', mysh::WORD_TYPE::ASSIGN}, 
    // {'+', mysh::WORD_TYPE::ADD}, 
    // {'-', mysh::WORD_TYPE::SUB}, 
    // {'*', mysh::WORD_TYPE::MUL}, 
    {'/', mysh::WORD_TYPE::DIV}, 
    {'>', mysh::WORD_TYPE::GTR}, 
    {'<', mysh::WORD_TYPE::LES}, 
    {',', mysh::WORD_TYPE::COMMA}, 
    {':', mysh::WORD_TYPE::COLON}
};

// 单词类型转打印信息
std::unordered_map<mysh::WORD_TYPE, std::string> word_type_to_message = {
    {mysh::WORD_TYPE::FUNCTION, "关键字function"}, 
    {mysh::WORD_TYPE::DECLARE, "关键字declare"}, 
    {mysh::WORD_TYPE::FOR, "关键字for"}, 
    {mysh::WORD_TYPE::IN, "关键字in"}, 
    {mysh::WORD_TYPE::TO, "关键字to"}, 
    {mysh::WORD_TYPE::IF, "关键字if"}, 
    {mysh::WORD_TYPE::ELIF, "关键字elif"}, 
    {mysh::WORD_TYPE::ELSE, "关键字else"}, 
    {mysh::WORD_TYPE::CALL, "关键字call"}, 
    {mysh::WORD_TYPE::RETURN, "关键字return"}, 
    {mysh::WORD_TYPE::RUN, "关键字run"}, 
    {mysh::WORD_TYPE::INPUT, "关键字input"}, 
    {mysh::WORD_TYPE::OUTPUT, "关键字output"}, 
    {mysh::WORD_TYPE::INT, "关键字int"}, 
    {mysh::WORD_TYPE::STRING, "关键字string"}, 
    {mysh::WORD_TYPE::ARRAY, "关键字array"}, 
    {mysh::WORD_TYPE::BOOL, "关键字bool"}, 
    {mysh::WORD_TYPE::VOID, "关键字void或空数据类型"}, 
    {mysh::WORD_TYPE::TRUE, "关键字true"}, 
    {mysh::WORD_TYPE::FALSE, "关键字false"}, 
    {mysh::WORD_TYPE::SEMICOLON, "分号"}, 
    {mysh::WORD_TYPE::LEFT_PARENTHESES, "左小括号"}, 
    {mysh::WORD_TYPE::RIGHT_PARENTHESES, "右小括号"}, 
    {mysh::WORD_TYPE::LEFT_SQUARE_BRACKETS, "左中括号"}, 
    {mysh::WORD_TYPE::RIGHT_SQUARE_BRACKETS, "右中括号"}, 
    {mysh::WORD_TYPE::LEFT_BRACE, "左大括号"}, 
    {mysh::WORD_TYPE::RIGHT_BRACE, "右大括号"}, 
    {mysh::WORD_TYPE::ASSIGN, "赋值"}, 
    // {mysh::WORD_TYPE::ADD, "加号"}, 
    // {mysh::WORD_TYPE::SUB, "减号"}, 
    // {mysh::WORD_TYPE::MUL, "乘号"}, 
    {mysh::WORD_TYPE::DIV, "除号"}, 
    {mysh::WORD_TYPE::GTR, "大于"}, 
    {mysh::WORD_TYPE::LES, "小于"}, 
    // {mysh::WORD_TYPE::GEQ, "大于等于"}, 
    // {mysh::WORD_TYPE::LEQ, "小于等于"}, 
    // {mysh::WORD_TYPE::EQU, "等于"}, 
    {mysh::WORD_TYPE::COMMA, "逗号"}, 
    {mysh::WORD_TYPE::COLON, "冒号"}, 
    {mysh::WORD_TYPE::EXPLANATORY_NOTE, "注释"}, 
    {mysh::WORD_TYPE::IDENTIFIER, "标识符"}, 
    {mysh::WORD_TYPE::INTEGER, "整型值"}, 
    {mysh::WORD_TYPE::ARRAY_VALUE, "数组值"}, 
    {mysh::WORD_TYPE::STRING_VALUE, "字符串值"}, 
    {mysh::WORD_TYPE::BOOL_VALUE, "布尔值"}, 
    {mysh::WORD_TYPE::COMMAND, "命令"}, 
    {mysh::WORD_TYPE::ILLEGAL_WORD, "非法单词"}
};

// 是否分析到run
bool if_run = false;

// 是否分析到左小括号
bool if_left_parentheses = false;
MY_SHELL_NAMESPACE_END

// mysh脚本每一行
std::vector<std::string> mysh::MyShellLexicalAnalyzer::every_line_of_mysh_script = std::vector<std::string>();

// mysh脚本行数
std::size_t mysh::MyShellLexicalAnalyzer::line_num = 0;

// 当前分析到的行的行号
std::int32_t mysh::MyShellLexicalAnalyzer::line_id = 0;

// 当前分析的行的长度
std::size_t mysh::MyShellLexicalAnalyzer::line_size = 0;

// 当前分析到的行的行内索引
std::int32_t mysh::MyShellLexicalAnalyzer::index_in_line = 0;

// 分析命令
mysh::Word mysh::MyShellLexicalAnalyzer::analyzeCommand()
{
    // 给当前正在分析的行起个别名
    std::string& cur_line = mysh::MyShellLexicalAnalyzer::every_line_of_mysh_script[mysh::MyShellLexicalAnalyzer::line_id];
    // 给行内索引起个别名
    std::int32_t& iil = mysh::MyShellLexicalAnalyzer::index_in_line;
    // 给当前分析的行的长度起个别名
    std::size_t& ls = mysh::MyShellLexicalAnalyzer::line_size;
    // 辅助分析的字符串
    std::string assist = std::string();
    // 开始分析
    while (iil < ls && 
        (cur_line[iil] != ')'))
    {
        assist += cur_line[iil];
        iil++;
    }
    mysh::if_run = false;
    mysh::if_left_parentheses = false;
    // 分析出命令
    return mysh::Word(assist, mysh::WORD_TYPE::COMMAND);
}

// 分析标识符或关键字
mysh::Word mysh::MyShellLexicalAnalyzer::analyzeIdentifierAndKeyword()
{
    // 给当前正在分析的行起个别名
    std::string& cur_line = mysh::MyShellLexicalAnalyzer::every_line_of_mysh_script[mysh::MyShellLexicalAnalyzer::line_id];
    // 给行内索引起个别名
    std::int32_t& iil = mysh::MyShellLexicalAnalyzer::index_in_line;
    // 给当前分析的行的长度起个别名
    std::size_t& ls = mysh::MyShellLexicalAnalyzer::line_size;
    // 辅助分析的字符串
    std::string assist = std::string();
    // 开始分析
    assist += cur_line[iil];
    iil++;
    while (iil < ls && 
        (cur_line[iil] == '_' || 
        (cur_line[iil] >= 'a' && cur_line[iil] <= 'z') || 
        (cur_line[iil] >= 'A' && cur_line[iil] <= 'Z') || 
        (cur_line[iil] >= '0' && cur_line[iil] <= '9')))
    {
        assist += cur_line[iil];
        iil++;
    }
    // 分析出关键字
    if (mysh::keywords.count(assist))
    {
        if (assist == "run")
        {
            mysh::if_run = true;
            mysh::if_left_parentheses = false;
        }
        return mysh::Word(assist, mysh::mysh_keyword_to_word_type[assist]);
    }
    // 分析出标识符
    return mysh::Word(assist, mysh::WORD_TYPE::IDENTIFIER);
}

// 分析整型数字
mysh::Word mysh::MyShellLexicalAnalyzer::analyzeInteger()
{
    // 给当前正在分析的行起个别名
    std::string& cur_line = mysh::MyShellLexicalAnalyzer::every_line_of_mysh_script[mysh::MyShellLexicalAnalyzer::line_id];
    // 给行内索引起个别名
    std::int32_t& iil = mysh::MyShellLexicalAnalyzer::index_in_line;
    // 给当前分析的行的长度起个别名
    std::size_t& ls = mysh::MyShellLexicalAnalyzer::line_size;
    // 辅助分析的字符串
    std::string assist = std::string();
    // 开始分析
    assist += cur_line[iil];
    iil++;
    while (iil < ls && 
        (cur_line[iil] >= '0' && cur_line[iil] <= '9'))
    {
        assist += cur_line[iil];
        iil++;
    }
    // 分析出整型数字
    return mysh::Word(assist, mysh::WORD_TYPE::INTEGER);
}

// 分析字符串
mysh::Word mysh::MyShellLexicalAnalyzer::analyzeString()
{
    // 给当前正在分析的行起个别名
    std::string& cur_line = mysh::MyShellLexicalAnalyzer::every_line_of_mysh_script[mysh::MyShellLexicalAnalyzer::line_id];
    // 给行内索引起个别名
    std::int32_t& iil = mysh::MyShellLexicalAnalyzer::index_in_line;
    // 给当前分析的行的长度起个别名
    std::size_t& ls = mysh::MyShellLexicalAnalyzer::line_size;
    // 辅助分析的字符串
    std::string assist = std::string();
    // 开始分析
    iil++;
    while (iil < ls && 
        (cur_line[iil] != '"'))
    {
        assist += cur_line[iil];
        iil++;
    }
    if(iil == ls) return mysh::Word(assist, mysh::WORD_TYPE::ILLEGAL_WORD);
    iil++;
    // 分析出字符串
    return mysh::Word(assist, mysh::WORD_TYPE::STRING_VALUE);
}

// 分析其他单词
mysh::Word mysh::MyShellLexicalAnalyzer::analyzeSpecialWords()
{
    // 给当前正在分析的行起个别名
    std::string& cur_line = mysh::MyShellLexicalAnalyzer::every_line_of_mysh_script[mysh::MyShellLexicalAnalyzer::line_id];
    // 给行内索引起个别名
    std::int32_t& iil = mysh::MyShellLexicalAnalyzer::index_in_line;
    // 给当前分析的行的长度起个别名
    std::size_t& ls = mysh::MyShellLexicalAnalyzer::line_size;
    // 当前字符
    char cur_ch = cur_line[iil];
    iil++;
    // 上个单词分析到了run，且当前字符为作小括号
    if (mysh::if_run && cur_ch == '(')
    {
        mysh::if_left_parentheses = true;
    }
    else
    {
        mysh::if_run = false;
    }
    // 开始分析
    if (mysh::single_characters.count(cur_ch))
    {
        // 当前字符不是最后一个字符
        if (iil < ls)
        {
            // // 下一个字符为等于，表明可能分析到双字符比较符
            // if (cur_line[iil] == '=')
            // {
            //     if (cur_ch == '>')
            //     {
            //         iil++;
            //         return mysh::Word(">=", mysh::WORD_TYPE::GEQ);
            //     }
            //     else if (cur_ch == '<')
            //     {
            //         iil++;
            //         return mysh::Word("<=", mysh::WORD_TYPE::LEQ);
            //     }
            //     else if (cur_ch == '=')
            //     {
            //         iil++;
            //         return mysh::Word("==", mysh::WORD_TYPE::EQU);
            //     }
            // }
            // 下一个字符和当前字符都为除号，表明分析到注释
            if (cur_line[iil] == '/' && cur_ch == '/')
            {
                iil++;
                std::string assist = std::string();
                while (iil < ls)
                {
                    assist += cur_line[iil];
                    iil++;
                }
                return mysh::Word(assist, mysh::WORD_TYPE::EXPLANATORY_NOTE);
            }
        }
        return mysh::Word(std::string() + cur_ch, mysh::mysh_single_character_to_word_type[cur_ch]);
    }
    return mysh::Word(std::string() + cur_ch, mysh::WORD_TYPE::ILLEGAL_WORD);
}

// 词法分析入口函数
std::vector<mysh::Word> mysh::MyShellLexicalAnalyzer::analyze(const std::vector<std::string>& every_line_of_mysh_script, bool if_print_error)
{
    // 初始化
    // mysh脚本行数
    mysh::MyShellLexicalAnalyzer::line_num = every_line_of_mysh_script.size();
    // 行数为0直接返回空
    if (mysh::MyShellLexicalAnalyzer::line_num == 0) return {};
    // 为mysh脚本行数起别名
    std::size_t& ln = mysh::MyShellLexicalAnalyzer::line_num;
    // mysh脚本每一行
    mysh::MyShellLexicalAnalyzer::every_line_of_mysh_script = every_line_of_mysh_script;
    // 为mysh脚本每一行起别名
    std::vector<std::string>& eloms = mysh::MyShellLexicalAnalyzer::every_line_of_mysh_script;
    // 当前分析到的行的行号
    mysh::MyShellLexicalAnalyzer::line_id = 0;
    // 当前分析到的行的行号起别名
    std::int32_t& li = mysh::MyShellLexicalAnalyzer::line_id;
    // 当前分析到的行的行内索引
    mysh::MyShellLexicalAnalyzer::index_in_line = 0;
    // 为当前分析到的行的行内索引起别名
    std::int32_t& iil = mysh::MyShellLexicalAnalyzer::index_in_line;
    // 答案数组
    std::vector<mysh::Word> ans;
    // 开始分析
    while (li < ln)
    {
        // 为当前正在分析的行起别名
        std::string& cur_line = eloms[li];
        // 当前分析的行的长度
        mysh::MyShellLexicalAnalyzer::line_size = cur_line.size();
        // 为当前分析的行的长度起别名
        std::size_t& ls = mysh::MyShellLexicalAnalyzer::line_size;
        // 分析当前行
        while (iil < ls)
        {
            // 跳过跳过符
            if (cur_line[iil] == mysh::default_skip_char)
            {
                iil++;
                continue;
            }
            // 分析命令
            if (mysh::if_run && mysh::if_left_parentheses)
            {
                ans.push_back(mysh::MyShellLexicalAnalyzer::analyzeCommand());
            }
            // 标识符和关键字
            else if ((cur_line[iil] >= 'a' && cur_line[iil] <= 'z') ||
                (cur_line[iil] >= 'A' && cur_line[iil] <= 'Z'))
            {
                ans.push_back(mysh::MyShellLexicalAnalyzer::analyzeIdentifierAndKeyword());
            }
            // 整型数字
            else if ((cur_line[iil] >= '0' && cur_line[iil] <= '9') || cur_line[iil] == '-')
            {
                ans.push_back(mysh::MyShellLexicalAnalyzer::analyzeInteger());
                mysh::if_run = false;
                mysh::if_left_parentheses = false;
            }
            // 字符串
            else if (cur_line[iil] == '"')
            {
                ans.push_back(mysh::MyShellLexicalAnalyzer::analyzeString());
                mysh::if_run = false;
                mysh::if_left_parentheses = false;
            }
            // 其他（特殊单字符等）
            else
            {
                ans.push_back(mysh::MyShellLexicalAnalyzer::analyzeSpecialWords());
            }
            if (if_print_error)
            {
                mysh::MyShellLexicalAnalyzer::printError(ans.back(), li, iil);
            }
        }
        li++;
        iil = 0;
    }
    return ans;
}

// 打印错误信息
void mysh::MyShellLexicalAnalyzer::printError(const mysh::Word& word, const std::int32_t& line_id, const std::int32_t& index_in_line)
{
    if (word.word_type != mysh::WORD_TYPE::ILLEGAL_WORD) return;
    std::cerr << "\033[33m" << "行号: " << "\033[31m" << line_id + 1 << "\033[33m" << "  行内索引: " << "\033[31m" << index_in_line + 1;
    std::cerr << "\033[33m" << "  单词: " << "\033[31m" << word.name << "\033[33m" << "  非法！" << "\033[0m" << std::endl;
}

// 打印词法分析信息
void mysh::MyShellLexicalAnalyzer::printAnalyzeMessage(const std::vector<mysh::Word>& all_words)
{
    for (const mysh::Word& word : all_words)
    {
        std::cerr << "\033[33m" << word.name << "\n  " << (word.word_type == mysh::WORD_TYPE::ILLEGAL_WORD ? "\033[31m" : "\033[32m") << mysh::word_type_to_message[word.word_type] << "\033[0m" << std::endl;
    }
}